package com.huidu.bitrade.service;

import com.alibaba.fastjson2.JSONObject;
import com.huidu.bitrade.constant.ContractRewardRecordType;
import com.huidu.bitrade.constant.TransactionType;
import com.huidu.bitrade.dao.ContractOrderEntrustDao;
import com.huidu.bitrade.dao.ContractRewardRecordRepository;
import com.huidu.bitrade.dao.MemberWeightUpperDao;
import com.huidu.bitrade.entity.*;
import com.huidu.bitrade.entity.*;
import com.huidu.bitrade.service.Base.BaseService;
import com.huidu.bitrade.util.BigDecimalUtils;
import com.huidu.bitrade.vo.RewardSetVo;
import com.querydsl.core.types.Predicate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ContractRewardRecordService extends BaseService {

    @Autowired
    private ContractRewardRecordRepository contractRewardRecordRepository;
    @Autowired
    private MemberService memberService;
    @Autowired
    private MemberWeightUpperService memberWeightUpperService;
    @Autowired
    private MemberWalletService memberWalletService;
    @Autowired
    private MemberTransactionService memberTransactionService;
    @Autowired
    private ContractOrderEntrustDao contractOrderEntrustDao;
    @Autowired
    private DataDictionaryService dataDictionaryService;
    @Autowired
    private MemberWeightUpperDao memberWeightUpperDao;
    @Autowired
    private RedisTemplate redisTemplate ;

    private String key = "admin-all-rewardset";
    private String agentKey = "agent-all-rewardset-";


    public Page<ContractRewardRecord> findAll(Predicate predicate, Pageable pageable) {
        if(Objects.isNull(predicate)){
            return contractRewardRecordRepository.findAll( pageable);
        }
        return contractRewardRecordRepository.findAll(predicate, pageable);
    }

    public ContractRewardRecord save(ContractRewardRecord rewardRecord) {
        return contractRewardRecordRepository.saveAndFlush(rewardRecord);
    }

    /**
     * 合约返佣
     * @param orderEntrust
     */
    @Transactional(rollbackFor = Exception.class)
    public void sendReward(ContractOrderEntrust orderEntrust) {

        BigDecimal lave = sendReturnReward(orderEntrust);
        //源用户
        Member member = memberService.findOne(orderEntrust.getMemberId());
        if(member==null){
            //源用户不存在
            return;
        }
        //剩余的 3-30%  4-70%
        Long firstId=3L;
        Long secondId=4L;
        BigDecimal rate1=BigDecimal.valueOf(0.3);
        BigDecimal rate2=BigDecimal.valueOf(0.7);

        Member member1 = memberService.findOne(firstId);
        Member member2 = memberService.findOne(secondId);


        if(lave.compareTo(BigDecimal.ZERO)==1){
            //第一个
            MemberWallet memberWallet = memberWalletService.findByCoinUnitAndMemberId("USDT", firstId);
            BigDecimal reward = BigDecimalUtils.mulDown(lave,rate1, 8);
            if (reward.compareTo(BigDecimal.ZERO) > 0) {
                memberWalletService.increaseBalance(memberWallet.getId(), reward);
                MemberTransaction memberTransaction = new MemberTransaction();
                memberTransaction.setAmount(reward);
                memberTransaction.setFee(BigDecimal.ZERO);
                memberTransaction.setMemberId(firstId);
                memberTransaction.setSymbol("USDT");
                memberTransaction.setType(TransactionType.PLATFORM_FEE_AWARD);
                memberTransaction.setDiscountFee("0");
                memberTransaction.setRealFee("0");
                memberTransaction = memberTransactionService.save(memberTransaction);
                ContractRewardRecord rewardRecord = new ContractRewardRecord();
                rewardRecord.setCoin(memberWallet.getCoin());
                rewardRecord.setContractOrderEntrust(orderEntrust);
                rewardRecord.setMember(member1);
                rewardRecord.setFromMember(member);
                rewardRecord.setType(ContractRewardRecordType.PLATFORM);
                rewardRecord.setNum(reward);
                this.save(rewardRecord);
            }
            //第二个
            MemberWallet memberWallet2 = memberWalletService.findByCoinUnitAndMemberId("USDT", secondId);
            BigDecimal reward2 = BigDecimalUtils.mulDown(lave,rate2, 8);
            if (reward2.compareTo(BigDecimal.ZERO) > 0) {
                memberWalletService.increaseBalance(memberWallet2.getId(), reward2);
                MemberTransaction memberTransaction = new MemberTransaction();
                memberTransaction.setAmount(reward2);
                memberTransaction.setFee(BigDecimal.ZERO);
                memberTransaction.setMemberId(secondId);
                memberTransaction.setSymbol("USDT");
                memberTransaction.setType(TransactionType.PLATFORM_FEE_AWARD);
                memberTransaction.setDiscountFee("0");
                memberTransaction.setRealFee("0");
                memberTransaction = memberTransactionService.save(memberTransaction);
                ContractRewardRecord rewardRecord = new ContractRewardRecord();
                rewardRecord.setCoin(memberWallet2.getCoin());
                rewardRecord.setContractOrderEntrust(orderEntrust);
                rewardRecord.setMember(member2);
                rewardRecord.setFromMember(member);
                rewardRecord.setType(ContractRewardRecordType.PLATFORM);
                rewardRecord.setNum(reward2);
                this.save(rewardRecord);
            }
        }


    }
    /**
     * 合约返佣
     * @param orderEntrust
     */
    @Transactional(rollbackFor = Exception.class)
    public BigDecimal sendReturnReward(ContractOrderEntrust orderEntrust) {
        BigDecimal lave = BigDecimal.ZERO;
        if(orderEntrust==null){
            return lave;
        }
        BigDecimal fee =BigDecimal.ZERO;
        ContractRewardRecordType type = ContractRewardRecordType.OPEN;
        if(orderEntrust.getEntrustType()== ContractOrderEntrustType.OPEN){
            fee = orderEntrust.getOpenFee();
            type = ContractRewardRecordType.OPEN;
        }else {
            fee = orderEntrust.getCloseFee();
            type = ContractRewardRecordType.CLOSE;
        }
        lave = fee;
        //修改返佣状态
        contractOrderEntrustDao.updateReward(orderEntrust.getId(),1);
        //获取上级关系
        MemberWeightUpper upper = memberWeightUpperService.findMemberWeightUpperByMemberId(orderEntrust.getMemberId());
        if(upper.getFirstMemberId()==null){
            //没有邀请人
            return lave;
        }
        //源用户
        Member member = memberService.findOne(orderEntrust.getMemberId());
        if(member==null){
            //源用户不存在
            return lave;
        }
        if(StringUtils.isEmpty(upper.getUpper())){
            //推荐关系不存在
            return lave;
        }
        List<Member> supers = memberService.findSuperPartnerMembersByIds(upper.getUpper());
        if(supers==null || supers.size()==0){
            //没有代理商或者不是代理商
            return lave;
        }
        //获取所有上级比重
        List<MemberWeightUpper> uppers = memberWeightUpperService.findAllByUpperIds(upper.getUpper());
        if(uppers==null || uppers.size()==0){
            //没有上级
            return lave;
        }

        DataDictionary commission = dataDictionaryService.findByBond("commission_rate");
        BigDecimal totalReward = BigDecimal.ZERO;
        if(commission==null){
            //未设置比例 默认50%
            totalReward = BigDecimalUtils.mulRound(fee,BigDecimal.valueOf(0.5), 8);
        }else {
            totalReward = BigDecimalUtils.mulRound(fee,BigDecimal.valueOf(Double.parseDouble(commission.getValue())), 8);
        }
        //当前已返比例
        int currentRate = 0;
        //先返佣自己
        if(upper.getRate()>0){
            currentRate=upper.getRate();
            //应返比例
            BigDecimal rate = BigDecimal.valueOf(upper.getRate()).divide(BigDecimal.valueOf(100),8,BigDecimal.ROUND_DOWN);
            //返佣
            MemberWallet memberWallet = memberWalletService.findByCoinUnitAndMemberId("USDT", upper.getMemberId());
            BigDecimal reward = BigDecimalUtils.mulDown(totalReward,rate, 8);
            if (reward.compareTo(BigDecimal.ZERO) > 0) {
                memberWalletService.increaseBalance(memberWallet.getId(), reward);
                MemberTransaction memberTransaction = new MemberTransaction();
                memberTransaction.setAmount(reward);
                memberTransaction.setFee(BigDecimal.ZERO);
                memberTransaction.setMemberId(upper.getMemberId());
                memberTransaction.setSymbol("USDT");
                memberTransaction.setType(TransactionType.CONTRACT_AWARD);
                memberTransaction.setDiscountFee("0");
                memberTransaction.setRealFee("0");
                memberTransaction = memberTransactionService.save(memberTransaction);
                ContractRewardRecord rewardRecord = new ContractRewardRecord();
                rewardRecord.setCoin(memberWallet.getCoin());
                rewardRecord.setContractOrderEntrust(orderEntrust);
                rewardRecord.setMember(member);
                rewardRecord.setFromMember(member);
                rewardRecord.setType(type);
                rewardRecord.setNum(reward);
                this.save(rewardRecord);
            }
        }
        for(MemberWeightUpper weightUpper : uppers){
            //获取用户信息
            Member upMember = memberService.findOne(weightUpper.getMemberId());
            int userRate = weightUpper.getRate();
            if("1".equals(upMember.getSuperPartner())){
                userRate=100;
            }
            //应返比例
            int releaseRate = userRate-currentRate;
            if(releaseRate<=0){
                //不返佣
                continue;
            }
            currentRate=userRate;
            BigDecimal rate = BigDecimal.valueOf(releaseRate).divide(BigDecimal.valueOf(100),8,BigDecimal.ROUND_DOWN);
            //返佣
            MemberWallet memberWallet = memberWalletService.findByCoinUnitAndMemberId("USDT", weightUpper.getMemberId());
            BigDecimal reward = BigDecimalUtils.mulDown(totalReward,rate, 8);
            if (reward.compareTo(BigDecimal.ZERO) > 0) {
                memberWalletService.increaseBalance(memberWallet.getId(), reward);
                MemberTransaction memberTransaction = new MemberTransaction();
                memberTransaction.setAmount(reward);
                memberTransaction.setFee(BigDecimal.ZERO);
                memberTransaction.setMemberId(weightUpper.getMemberId());
                memberTransaction.setSymbol("USDT");
                memberTransaction.setType(TransactionType.CONTRACT_AWARD);
                memberTransaction.setDiscountFee("0");
                memberTransaction.setRealFee("0");
                memberTransaction = memberTransactionService.save(memberTransaction);
                ContractRewardRecord rewardRecord = new ContractRewardRecord();
                rewardRecord.setCoin(memberWallet.getCoin());
                rewardRecord.setContractOrderEntrust(orderEntrust);
                rewardRecord.setMember(upMember);
                rewardRecord.setFromMember(member);
                rewardRecord.setType(type);
                rewardRecord.setNum(reward);
                this.save(rewardRecord);
            }
            if(currentRate>=100){
                //停止
                break;
            }
        }
        lave = lave.subtract(totalReward);


        //平级奖励
        if(supers.size()>1){
            DataDictionary levelReward = dataDictionaryService.findByBond("level_reward_rate");
            BigDecimal rate = BigDecimal.ZERO;
            if(commission==null){
                //未设置比例 默认2%
                rate = BigDecimal.valueOf(0.02);
            }else {
                rate = BigDecimal.valueOf(Double.parseDouble(levelReward.getValue()));
            }

            //返佣
            MemberWallet memberWallet = memberWalletService.findByCoinUnitAndMemberId("USDT", supers.get(1).getId());
            BigDecimal reward = BigDecimalUtils.mulDown(totalReward,rate, 8);
            if (reward.compareTo(BigDecimal.ZERO) > 0) {
                memberWalletService.increaseBalance(memberWallet.getId(), reward);
                MemberTransaction memberTransaction = new MemberTransaction();
                memberTransaction.setAmount(reward);
                memberTransaction.setFee(BigDecimal.ZERO);
                memberTransaction.setMemberId(supers.get(1).getId());
                memberTransaction.setSymbol("USDT");
                memberTransaction.setType(TransactionType.LEVEL_AWARD);
                memberTransaction.setDiscountFee("0");
                memberTransaction.setRealFee("0");
                memberTransaction = memberTransactionService.save(memberTransaction);
                ContractRewardRecord rewardRecord = new ContractRewardRecord();
                rewardRecord.setCoin(memberWallet.getCoin());
                rewardRecord.setContractOrderEntrust(orderEntrust);
                rewardRecord.setMember(supers.get(1));
                rewardRecord.setFromMember(member);
                rewardRecord.setType(ContractRewardRecordType.LEVEL);
                rewardRecord.setNum(reward);
                this.save(rewardRecord);
                lave = lave.subtract(reward);
            }
        }
        return lave;
    }

    public RewardSetVo findAllRewardSetVo() {
        RewardSetVo vo = null;
        ValueOperations<String,String> opt = redisTemplate.opsForValue();
        String voJson = opt.get(key);
        if(voJson!=null){
            vo = JSONObject.parseObject(voJson,RewardSetVo.class);
            return vo;
        }
        vo = new RewardSetVo();
        vo.setName("超级管理");
        vo.setRate("");
        log.info("===========返佣比例：查询所有用户开始：{}=========",System.currentTimeMillis());
        //查询所有用户
        List<Member> memberList = memberService.findAll();
        log.info("===========返佣比例：查询所有用户结束：{}=========",System.currentTimeMillis());
        //查询所有返佣记录
        log.info("===========返佣比例：查询所有返佣记录开始：{}=========",System.currentTimeMillis());
        List<MemberWeightUpper> memberWeightUppers = memberWeightUpperService.findAll();
        log.info("===========返佣比例：查询所有返佣记录结束：{}=========",System.currentTimeMillis());
        //寻找所有推荐人为空的
        List<Member> firstMemberList = memberList.stream().filter(s-> Objects.isNull(s.getInviterId())).collect(Collectors.toList());
        List<RewardSetVo> children = new ArrayList<>();
        Map<Long,List<Member>> memberMap = memberList.stream().filter(s->Objects.nonNull(s.getInviterId()))
                .collect(Collectors.groupingBy(Member::getInviterId));
        Map<Long,MemberWeightUpper> upperMap = memberWeightUppers.stream().collect(Collectors.toMap(MemberWeightUpper::getMemberId, Function.identity()));
        Map<Long,Member> longMemberMap = firstMemberList.stream().collect(Collectors.toMap(Member::getId, Function.identity()));
        log.info("===========返佣比例：处理数据开始：{}=========",System.currentTimeMillis());
        for(Member member:firstMemberList){
            if(CollectionUtils.isEmpty(memberMap.get(member.getId()))){
                continue;
            }
            children.add(findRewardChild(longMemberMap,upperMap,memberMap,member,false,memberMap.get(member.getId())));
        }
        log.info("===========返佣比例：处理数据结束：{}=========",System.currentTimeMillis());
        vo.setChildren(children);
        //放入缓存
        String jsonString = JSONObject.toJSONString(vo);
        opt.set(key,jsonString);
        return vo;
    }

    /**
     * 递归查询分佣比例
     * @param longMemberMap 所有用户的map集合
     * @param upperMap 分佣allmap集合
     * @param memberMap 每个推荐人下级用户集合
     * @param member 当前用户
     * @param canUpdate false
     * @param childrenList 下级所有用户
     * @return
     */
    private RewardSetVo findRewardChild(Map<Long,Member> longMemberMap,Map<Long,MemberWeightUpper> upperMap,Map<Long,List<Member>> memberMap,Member member,Boolean canUpdate,List<Member> childrenList){
        RewardSetVo vo = new RewardSetVo();
        vo.setCanUpdate(canUpdate);
        if("1".equals(member.getSuperPartner())){
            vo.setRate("100%");
            vo.setCanUpdate(false);
        }else {
            MemberWeightUpper memberWeightUpper = upperMap.get(member.getId());
            if(Objects.isNull(memberWeightUpper)){
                memberWeightUpper = saveMemberWeightUpper(member,longMemberMap.get(member.getInviterId()),longMemberMap);
            }
            vo.setRate(memberWeightUpper.getRate()+"%");
        }
        vo.setName(member.getUsername());
        vo.setRealName(StringUtils.isNotEmpty(member.getRealName()) ?member.getRealName():"未实名");
        vo.setId(String.valueOf(member.getId()));
        List<RewardSetVo> children = new ArrayList<>();
        for(Member member1:childrenList){
            if(CollectionUtils.isEmpty(memberMap.get(member1.getId()))){
                continue;
            }
            children.add(this.findRewardChild(longMemberMap,upperMap,memberMap,member1,canUpdate,memberMap.get(member1.getId())));
        }
        vo.setChildren(children);
        return vo;
    }

    public MemberWeightUpper saveMemberWeightUpper(Member member,Member inviter,Map<Long,Member> longMemberMap) {
        MemberWeightUpper memberWeightUpper = new MemberWeightUpper();
        //找上级 如果有上级
        if(Objects.nonNull(inviter)){
            //有上级
            MemberWeightUpper upper = this.saveMemberWeightUpper(inviter,longMemberMap.get(inviter.getInviterId()),longMemberMap);
            memberWeightUpper.setFirstMemberId(upper.getFirstMemberId());
            memberWeightUpper.setRate(0);
            memberWeightUpper.setMemberId(member.getId());
            String uppers = upper.getUpper();
            if(StringUtils.isEmpty(uppers)){
                uppers = upper.getMemberId().toString();
            }else {
                uppers = uppers+","+upper.getMemberId();
            }
            memberWeightUpper.setUpper(uppers);
        }else {
            //最上级
            if("1".equals(member.getSuperPartner())){
                memberWeightUpper.setRate(100);
            }else {
                memberWeightUpper.setRate(0);
            }
            memberWeightUpper.setFirstMemberId(member.getId());
            memberWeightUpper.setMemberId(member.getId());
            memberWeightUpper.setUpper(null);
        }
        memberWeightUpper = memberWeightUpperDao.save(memberWeightUpper);
        return memberWeightUpper;
    }


    /**
     * 为代理商平台提供
     * @param id
     * @return
     */
    public RewardSetVo findRewardSetVoById(Long id){
        String key = agentKey+id;
        RewardSetVo vo = null;
        ValueOperations<String,String> opt = redisTemplate.opsForValue();
        String voJson = opt.get(key);
        if(voJson!=null){
            vo = JSONObject.parseObject(voJson,RewardSetVo.class);
            return vo;
        }
        vo = findRewardSetVoByPid(id,id,true);
        //放入缓存
        String jsonString = JSONObject.toJSONString(vo);
        opt.set(key,jsonString);
        return vo;
    }

    public void clearRewardSetVoById(Long id) {
        String key = agentKey+id;
        ValueOperations<String,String> opt = redisTemplate.opsForValue();
        opt.set(key,null);
    }
    private RewardSetVo findRewardSetVoByPid(Long userId,Long pid,Boolean canUpdate){
        RewardSetVo vo = new RewardSetVo();
        vo.setCanUpdate(canUpdate);
        //推荐人
        Member member = memberService.findOne(pid);
        if("1".equals(member.getSuperPartner())){
            vo.setRate("100%");
            vo.setCanUpdate(false);
            if(userId.longValue()!=pid){
                canUpdate=false;
            }
        }else {
            MemberWeightUpper upper = memberWeightUpperService.saveMemberWeightUpper(member);
            vo.setRate(upper.getRate()+"%");
        }
        vo.setName(member.getUsername());
        vo.setRealName((member.getRealName()!=null || "".equals(member.getRealName()))?member.getRealName():"未实名");
        vo.setId(member.getId()+"");
        List<RewardSetVo> children = new ArrayList<>();
        List<Member> members = memberService.findPromotionMember(pid);
        for(Member member1:members){
            children.add(this.findRewardSetVoByPid(userId,member1.getId(),canUpdate));
        }
        vo.setChildren(children);
        return vo;
    }

    public void clearAllRewardSetVo() {
        ValueOperations<String,String> opt = redisTemplate.opsForValue();
        opt.set(key,null);
    }
}
